package base;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.math.BigDecimal;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.taobao.api.internal.mapping.ApiField;

/**
 * 反射工具类
 */
public class InvokerUtil {
  public final static Logger log = LoggerFactory.getLogger(InvokerUtil.class);

  /**
   * 以MAP的KEY作为字段名VALUE作为值调用方法
   * 
   * @param obj
   * @param params
   */
  public static void invokeMethod(Object obj, Map params) {
    Set<Field> fieds = new HashSet<Field>();
    // 获取所有字段
    findAllFields(obj.getClass(), fieds);

    for (Field field : fieds) {
      for (Iterator<Map.Entry<String, Object>> i = params.entrySet().iterator(); i.hasNext();) {
        Entry<String, Object> next = i.next();

        if (next.getKey().toString().equals(field.getName())) {
          invokeSet(obj, field, next.getValue());
        }
      }
    }
  }

  public static Object invokeGet(Object obj, Field field) {
    Class objClazz = obj.getClass();

    try {

      if (boolean.class.equals(field.getType()) || Boolean.class.equals(field.getType())) {
        try {
          if (field.getName().contains("is")) {
            return objClazz.getMethod(field.getName()).invoke(obj);
          }
          return objClazz.getMethod("is" + capFirst(field.getName())).invoke(obj);
        } catch (Exception e1) {
        }
      }

      return objClazz.getMethod("get" + capFirst(field.getName())).invoke(obj);
    } catch (Exception e) {
      try {
        return field.get(obj);
      } catch (Exception e1) {
        log.error(e.getMessage(), e1);
      }
      return null;
    }
  }

  private static String capFirst(String name) {
    String string = name;
    if (string.length() == 0) {
      return string;
    }
    return ("" + string.charAt(0)).toUpperCase() + string.substring(1);

  }

  public static void invokeSet(Object obj, Field field, Object fieldValue) {
    Class objClazz = obj.getClass();

    try {
      objClazz.getMethod("set" + capFirst(field.getName()), field.getType()).invoke(obj, fieldValue);
    } catch (Exception e) {
      try {
        field.set(objClazz, fieldValue);
      } catch (Exception e1) {
        log.error(e.getMessage(), e);

      }
    }
  }

  public static Object parseType(Field field, Object value) {
    if (value == null || StringUtils.isEmpty(value.toString())) {
      return null;
    }
    Class<?> typeClass = field.getType();
    try {
      if (String.class.isAssignableFrom(typeClass)) {
        return value.toString();
      } else if (Long.class.isAssignableFrom(typeClass)) {
        return Long.parseLong(value.toString());
      } else if (Integer.class.isAssignableFrom(typeClass)) {
        return Integer.parseInt(value.toString());
      } else if (Boolean.class.isAssignableFrom(typeClass)) {
        if ("1".equals(value)) {
          value = "true";
        }
        return Boolean.valueOf(value.toString());
      } else if (Double.class.isAssignableFrom(typeClass)) {
        return Double.parseDouble(value.toString());
      } else if (Date.class.isAssignableFrom(typeClass)) {

        return getDate(value);
      }
    } catch (Exception e) {
      log.error(e.getMessage(), e);
    }
    return null;
  }

  public static Date getDate(Object value) {
    try {
      return new SimpleDateFormat("yyyy-MM-dd hh:mm:ss").parse(value.toString());
    } catch (Exception e) {
      try {
        return new SimpleDateFormat("MM/dd/yyyy HH:mm:ss").parse(value.toString());
      } catch (Exception e1) {
        try {
          return new SimpleDateFormat("MM/dd/yyyy").parse(value.toString());
        } catch (Exception e2) {
          try {
            return new SimpleDateFormat("yyyy-MM-dd").parse(value.toString());
          } catch (Exception e3) {
            return null;
          }
        }
      }
    }
  }

  public static String findApiFieldValue(Field field) {
    ApiField apianno = field.getAnnotation(ApiField.class);
    if (apianno == null) {
      return null;
    }
    return apianno.value();
  }

  /**
   * 获得全部字段包括继承的，取得的字段按照字母排序A-Z-a-z
   * 
   * @param clazz
   *          对象类型
   * @return 所有字段不包括被static
   */
  public static Set<Field> getFields(Class clazz) {
    Set<Field> fieldSet = new HashSet<Field>();
    findAllFields(clazz, fieldSet);

    for (Iterator<Field> i = fieldSet.iterator(); i.hasNext();) {
      if (skipField(i.next())) {
        i.remove();
      }
    }

    List<Field> fieldList = new ArrayList<Field>();
    fieldList.addAll(fieldSet);

    fieldSet.clear();
    fieldSet.addAll(fieldList);

    return fieldSet;
  }

  /**
   * 忽略字段（被static或<code>@Transient</code>或Transient所修饰的字段）
   * 
   * @param field
   *          字段
   * @return true 忽略
   */
  public static boolean skipField(Field field) {
    int modifiers = field.getModifiers();
    return Modifier.isStatic(modifiers);
  }

  public static void findAllFields(Class clazz, Set<Field> found) {
    Field[] fields = clazz.getDeclaredFields();
    for (int i = 0; i < fields.length; i++) {
      found.add(fields[i]);
    }
    Class sClazz = clazz.getSuperclass();
    if (sClazz != null && sClazz != Object.class) {
      findAllFields(sClazz, found);
    }
  }

  /**
   * 给对象的某个成员设置（set）
   * 
   * @param o
   *          对象
   * @param filedName
   *          字段名
   * @param value
   *          值
   */
  public static void setValue(Object o, Class objClazz, Field field, Object value) {
    if (value == null) {
      return;
    }

    Class fieldClazz = field.getType();

    Object fieldValue = null;

    if (String.class.equals(fieldClazz)) {
      fieldValue = value.toString();
    } else if (Integer.class.equals(fieldClazz) || int.class.equals(fieldClazz)) {
      fieldValue = new Integer(value.toString());
    } else if (Long.class.equals(fieldClazz) || long.class.equals(fieldClazz)) {
      fieldValue = new Long(value.toString());
    } else if (java.util.Date.class.equals(fieldClazz)) {
      fieldValue = new Date(((java.sql.Timestamp) value).getTime());
    } else if (Float.class.equals(fieldClazz) || float.class.equals(fieldClazz)) {
      fieldValue = new Float(value.toString());
    } else if (Double.class.equals(fieldClazz) || double.class.equals(fieldClazz)) {
      fieldValue = new Double(value.toString());
    } else if (BigDecimal.class.equals(fieldClazz)) {
      fieldValue = new BigDecimal(value.toString());
    } else if (Boolean.class.equals(fieldClazz) || boolean.class.equals(fieldClazz)) {
      if (value.toString().equals("1") || value.toString().equalsIgnoreCase("true")) {
        value = "true";
      }

      fieldValue = new Boolean(value.toString());
    } else {

      return;
    }

    InvokerUtil.invokeSet(o, field, fieldValue);
  }
}
